package com.property.manage.service.rent;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guardchina.framework.mybatis.model.CustomPage;
import com.guardchina.framework.util.exception.BusinessException;
import com.guardchina.framework.util.utils.NumberToCn;
import com.property.manage.dao.flowingWater.FlowingWaterExpandMapper;
import com.property.manage.dao.flowingWater.FlowingWaterMapper;
import com.property.manage.dao.rent.RentPaymentMapper;
import com.property.manage.enums.WalletType;
import com.property.manage.model.flowingWater.FlowingWaterEntity;
import com.property.manage.model.flowingWater.FlowingWaterExpandEntity;
import com.property.manage.model.print.PayBillVo;
import com.property.manage.model.rent.HouseArrearsEntity;
import com.property.manage.model.rent.RentEntity;
import com.property.manage.model.rent.RentPaymentEntity;
import com.property.manage.model.rent.RentPaymentVo;
import com.property.manage.model.resource.BuildingVo;
import com.property.manage.model.system.SysSet;
import com.property.manage.model.system.User;
import com.property.manage.service.flowingWater.FlowingWaterService;
import com.property.manage.service.flowingWater.WalletService;
import com.property.manage.service.resource.BuildingService;
import com.property.manage.service.system.SnowflakeIdWorker;
import com.property.manage.service.system.SysSetService;
import com.property.manage.service.system.UserService;
import com.property.manage.util.ExportUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;


@Service
@Slf4j
public class RentPaymentService {
    @Autowired
    private RentPaymentMapper rentPaymentMapper;
    @Autowired
    private SysSetService sysSetService;
    @Autowired
    private BuildingService buildingService;
    @Autowired
    private UserService userService;
    @Autowired
    private FlowingWaterService flowingWaterService;
    @Autowired
    private WalletService walletService;
    @Autowired
    private HouseArrearsService houseArrearsService;

    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;

    @Autowired
    private HouseRentService houseRentService;

    @Autowired
    private RentService rentService;

    @Autowired
    private FlowingWaterMapper flowingWaterMapper;

    @Autowired
    private FlowingWaterExpandMapper flowingWaterExpandMapper;

    @Value("${timed.patee}")
    private String patee;

    @Value("${timed.receiveUnit}")
    private String receiveUnit;

    public CustomPage<RentPaymentVo> page(Long pageNo, Long pageSize, Integer villageId, Integer building, Integer unit, String roomNumber,
                                          String startTime, String endTime) {
        Page<RentPaymentVo> page = new Page<>(pageNo, pageSize);
        IPage<RentPaymentVo> village = rentPaymentMapper.getHouseRentPage(page, villageId, building, unit, roomNumber, startTime, endTime);
        List<RentPaymentVo> records = village.getRecords();
        if (records.isEmpty()) {
            return new CustomPage<>(village);
        }
        for (RentPaymentVo record : records) {
            record.setPayType(sysSetService.getDesc(SysSet.PAY_TYPE, record.getType().toString()));
        }
        return new CustomPage<>(village);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deletePay(Integer id) {

        RentPaymentEntity payment = getNormalById(id);

        RentEntity rentEntity = rentService.getById(payment.getRentId());

        if (RentPaymentEntity.OTHER_TYPE_NORMAL.equals(payment.getOtherType())) {
            deleteNormal(rentEntity, payment);
        } else {

            deleteArrears(payment);
        }
    }

    private RentPaymentEntity getNormalById(Integer id) {
        QueryWrapper<RentPaymentEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id);
        wrapper.eq("state", RentPaymentEntity.STATE_NORMAL);

        return Optional.ofNullable(rentPaymentMapper.selectOne(wrapper)).orElseThrow(() -> new BusinessException("缴费记录不存在", String.format("id: %s", id)));
    }

    private void deleteNormal(RentEntity rentEntity, RentPaymentEntity paymentEntity) {
        deletePayment(paymentEntity.getId());

        walletService.deposit(paymentEntity.getBuildingId(), paymentEntity.getPreDeposit(), WalletType.RENT);

        int year = Integer.parseInt(paymentEntity.getRemark().substring(0, 4));

        int month = Integer.parseInt(paymentEntity.getRemark().substring(4, 6));


        HouseArrearsEntity houseArrearsEntity = houseRentService.getHouseArrearsEntity(rentEntity.getId(), rentEntity.getVillageId(), year, month, rentEntity, "操作失败");

        ArrayList<HouseArrearsEntity> arrears = new ArrayList();
        arrears.add(houseArrearsEntity);

        houseArrearsService.add(arrears);
    }

    private void deleteArrears(RentPaymentEntity paymentEntity) {
        deletePayment(paymentEntity.getId());
        //缴费时使用了预存，则增加预存
        if (paymentEntity.getPreDeposit().compareTo(BigDecimal.ZERO) > 0) {
            walletService.deposit(paymentEntity.getBuildingId(), paymentEntity.getPreDeposit(), WalletType.RENT);
        }
        //缴费时转存了预存，则减少预存
        if (paymentEntity.getReturnDeposit().compareTo(BigDecimal.ZERO) > 0) {
            walletService.updateExpenditure(paymentEntity.getBuildingId(), paymentEntity.getReturnDeposit(), WalletType.RENT);
        }

        houseArrearsService.undoCharge(paymentEntity.getId());
    }

    private void deletePayment(Integer id) {
        UpdateWrapper<RentPaymentEntity> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("state", RentPaymentEntity.STATE_DELETED);

        rentPaymentMapper.update(null, wrapper);
    }

    public Integer add(User user, Integer rentId, Integer villageId, Integer buildingId, Integer type,
                       BigDecimal money, BigDecimal propertyFee, BigDecimal otherFee, BigDecimal total,
                       BigDecimal preDeposit, BigDecimal cash, BigDecimal returnDeposit, String billNo, String remark,
                       BigDecimal shouldPay, Byte otherType) {

        log.info("房屋出租缴费：userName[{}], buildingId[{}], rentId[{}], total[{}], money[{}], propertyFee[{}], otherFee[{}],cash[{}], preDeposit[{}], returnDeposit[{}], payType[{}], remark[{}], billNo[{}]", user.getUserName(), buildingId, remark, total, money, propertyFee, otherFee, cash, preDeposit, returnDeposit, type, remark, billNo);
        if (cash.add(preDeposit).subtract(returnDeposit).compareTo(total) != 0) {
            throw new BusinessException("缴费金额不一致", "cash.add(preDeposit).subtract(returnDeposit).compareTo(money)");
        }

        if (preDeposit.compareTo(BigDecimal.ZERO) > 0) {
            walletService.updateExpenditure(buildingId, preDeposit, WalletType.RENT);
        }

        if (returnDeposit.compareTo(BigDecimal.ZERO) < 0) {
            walletService.changeDeposit(buildingId, returnDeposit, WalletType.RENT);
        }

        BigDecimal balance = walletService.findBalance(buildingId, WalletType.RENT);

        RentPaymentEntity entity = new RentPaymentEntity();
        entity.setRentId(rentId);
        entity.setBuildingId(buildingId);
        entity.setVillageId(villageId);
        entity.setName(buildingService.findAddress(buildingId));
        entity.setCreateTime(LocalDate.now());
        entity.setMoney(money);
        entity.setOtherFee(otherFee);
        entity.setPropertyFee(propertyFee);
        entity.setDrawer(user.getUserName());
        entity.setTotalMoney(total);
        entity.setCash(new BigDecimal(0));
        entity.setType(type);
        entity.setPreDeposit(preDeposit);
        entity.setReturnDeposit(returnDeposit);
        entity.setDBalance(balance);
        entity.setBillOn(billNo);
        entity.setRemark(remark);

        entity.setOtherType(otherType);

        entity.setState(RentPaymentEntity.STATE_NORMAL);


        rentPaymentMapper.insert(entity);


        //创建流水
        //user 用户信息，buildingId 楼栋ID，shouldPay 应收金额，realFee 实付金额，subtractFee 差额，preStorage 使用预存金额，
        // expenditure 当前预存，cash 现金，small 转存的零钱存入流水，listOfCharges 收费名目， type 收费类型， explain 说明， remarks 备注，
        // payType 付款方式 1现金 2微信 3支付宝 4统一划扣 ， billNo  票据编号， otherType 状态 0-正常收费 1-欠费收取

        FlowingWaterExpandEntity flowingWaterEntity = flowingWaterService.createFlowingWaterEntityByBuildingId(user, buildingId,
                shouldPay, total, BigDecimal.ZERO, preDeposit, balance, BigDecimal.ZERO, BigDecimal.ZERO,
                "房屋租金划扣", 1, remark, otherType == 0 ? "批量划扣" : "欠取收费",
                SysSet.PAY_TYPE_CODE_FOUR, billNo, otherType);
        flowingWaterExpandMapper.insert(flowingWaterEntity);

        return entity.getId();
    }


    private List<HouseArrearsEntity> getEntities(List<Integer> ids, RentPaymentEntity entity) {
        List<HouseArrearsEntity> list = new ArrayList<>();
        for (Integer id : ids) {
            HouseArrearsEntity arrearsEntity = new HouseArrearsEntity();
            arrearsEntity.setState(2);
            arrearsEntity.setPayId(entity.getId());
            arrearsEntity.setId(id);
            list.add(arrearsEntity);
        }
        return list;
    }


    public void updateBillNo(Integer id, String billNo) {
        UpdateWrapper<RentPaymentEntity> up = new UpdateWrapper<>();
        up.eq("id", id);
        up.set("bill_on", billNo);
        rentPaymentMapper.update(null, up);
    }

    //缴费记录下载
    public void download(Integer villageId, Integer building, Integer unit, String roomNumber, String startTime, String endTime, HttpServletRequest request, HttpServletResponse response) {
        String str = "房屋租金缴费报表";
        XSSFWorkbook workbook = new XSSFWorkbook();
        XSSFSheet sheet = workbook.createSheet(str);
        //创建第一行
        XSSFRow row = sheet.createRow(0);
        //设置表头格式
        List<String> titles = Arrays.asList("小区", "付款方", "金额", "物业费",
                "租金",
                "其他费用", "使用预存"
                , "现金", "预存余额",
                "时间");

        for (int i = 0; i <= 9; i++) {
            sheet.setColumnWidth(i, 4500);
            row.createCell(i).setCellValue(titles.get(i));

        }
        List<RentPaymentVo> rentPage = rentPaymentMapper.getHouseRents(villageId, building, unit, roomNumber, startTime, endTime);
        //将所有单元格设置成文本格式
        if (!rentPage.isEmpty()) {
            for (int i = 1; i <= (rentPage.size()); i++) {
                RentPaymentVo vo = rentPage.get(i - 1);
                XSSFRow row1 = sheet.createRow(i);
                row1.createCell(0).setCellValue(vo.getVillageName());
                row1.createCell(1).setCellValue(vo.getName());
                row1.createCell(2).setCellValue(String.valueOf(vo.getTotalMoney()));
                row1.createCell(3).setCellValue(String.valueOf(vo.getPropertyFee()));
                row1.createCell(4).setCellValue(String.valueOf(vo.getMoney()));
                row1.createCell(5).setCellValue(String.valueOf(vo.getOtherFee()));
                row1.createCell(6).setCellValue(String.valueOf(vo.getPreDeposit()));
                row1.createCell(7).setCellValue(String.valueOf(vo.getCash()));
                row1.createCell(8).setCellValue(String.valueOf(vo.getDBalance()));
                row1.createCell(9).setCellValue(String.valueOf(vo.getCreateTime()));
            }
        }

        String fileName = "房屋租金报表.xlsx";

        ExportUtil.exportExcel(request, response, fileName, workbook);

    }

    public PayBillVo payBill(Integer id) {

        RentPaymentVo houseRent = rentPaymentMapper.getHouseRent(id);
        RentEntity rentEntity = rentService.getById(houseRent.getRentId());
        BuildingVo building = buildingService.findBuilding(rentEntity.getBuildingId());

        PayBillVo payBillVo = new PayBillVo();

        payBillVo.setTitle(patee + "收款收据");

        payBillVo.setBillNo(houseRent.getBillOn());

        payBillVo.setVillageName(houseRent.getVillageName());

        payBillVo.setAddress(building.getBuilding() + "-" + building.getUnit() + "-" + building.getRoomNumber());

        payBillVo.setOwnerName(rentEntity.getName());

        payBillVo.setPayTime(houseRent.getCreateTime());

        payBillVo.setFeeType("房屋租金");

        payBillVo.setMoney(houseRent.getTotalMoney());

        payBillVo.setPropertyMoney(houseRent.getPropertyFee());
        payBillVo.setRentMoney(houseRent.getMoney());
        payBillVo.setOtherMoney(houseRent.getOtherFee());

        payBillVo.setAdvanceBalance(houseRent.getDBalance());

        payBillVo.setRemark(houseRent.getRemark());

        payBillVo.setRealAmount(houseRent.getTotalMoney());

        payBillVo.setChineseAmount(NumberToCn.number2Cn(houseRent.getTotalMoney()));

        payBillVo.setPayee(houseRent.getDrawer());

        payBillVo.setReceiveUnit(receiveUnit);

        return payBillVo;
    }

}
